#include "device/ml307/AtNetworkHttpML307.h"

#define HTTP_BASE_INPUT_FLAG ">"
#define HTTP_BASE_OUTPUT_FLAG "+MHTTPURC: \"recv\","

#define HTTP_BASE_READY_0 "AT+MHTTPCREATE=\"%s\"\r\n" // 配置请求参数
#define HTTP_BASE_READY_0R "+MHTTPCREATE:"

#define HTTP_BASE_CONFIG_1 "AT+MHTTPCFG=\"cached\",%d,1"
#define HTTP_BASE_CONFIG_2 "AT+MHTTPCFG=\"header\",%d,\"Connection: close\"\r\n" // 配置请求参数

#define HTTP_BASE_REQUEST0 "AT+MHTTPCONTENT=%d,0,%d\r\n"  // 发送POST请求数据
#define HTTP_BASE_REQUEST1 "AT+MHTTPREQUEST=%d,%d,%d\r\n" // 执行HTTP请求操作

#define HTTP_BASE_READ_CMD "AT+MHTTPREAD=%d,1,0\r\n"
#define HTTP_BASE_READ_RES "+MHTTPREAD:"

#define HTTP_BASE_CLOSE "AT+MHTTPDEL=%d\r\n" // HTTP请求已完成，释放相关资源

/**
 * 发起GET请求
 */
size_t AtNetworkHttpML307::get0(HttpCallback fun, std::string url, uint32_t timeout) {
  const char *serverHost = url.substr(0, url.find('/', 8)).c_str();
  const char *serverPath = url.substr(url.find('/', 8)).c_str();

  if (fun != nullptr && this->executeRequest(fun, serverHost) == AT_RCODE1) {
    return this->executeResponse(fun, 1, serverPath);
  }

  // -------------------------------------------------------------------
  // 释放HTTP资源
  // -------------------------------------------------------------------
  this->device->streamPrintfClear(HTTP_BASE_CLOSE, this->tid);
  this->device->streamReleaseInvalidLegacyData();

  return CONNECT_ERR_0;
}

/**
 * 发起POST请求
 */
size_t AtNetworkHttpML307::post0(HttpCallback fun, std::string url, char *body, uint32_t timeout) {
  const char *serverHost = url.substr(0, url.find('/', 8)).c_str();
  const char *serverPath = url.substr(url.find('/', 8)).c_str();

  if (fun != nullptr && this->executeRequest(fun, serverHost) == AT_RCODE1) {
    this->device->streamPrintfClear(HTTP_BASE_REQUEST0, this->tid, strlen(body));
    if (this->wait(5000, HTTP_BASE_INPUT_FLAG) == AT_RCODE1) {
      this->device->streamWriteClear(body, GSM_NL);
    } else {
      goto http_exit;
    }

    return this->executeResponse(fun, 2, serverPath);
  }

// -------------------------------------------------------------------
// 释放HTTP资源
// -------------------------------------------------------------------
http_exit:
  this->device->streamPrintfClear(HTTP_BASE_CLOSE, this->tid);
  this->device->streamReleaseInvalidLegacyData();

  return CONNECT_ERR_0;
}

size_t AtNetworkHttpML307::executeResponse(HttpCallback fun, uint8_t method, const char *serverPath) {
  this->device->streamPrintfClear(HTTP_BASE_REQUEST1, this->tid, method, strlen(serverPath));
  if (this->device->wait(HTTP_BASE_INPUT_FLAG) == AT_RCODE1) {
    this->device->streamWriteClear(serverPath, GSM_NL);
  } else {
    return CONNECT_ERR_0;
  }

  if (this->wait(80000, HTTP_BASE_OUTPUT_FLAG) != AT_RCODE1) {
    return CONNECT_ERR_0;
  }

  // -------------------------------------------------------------------
  // 发送读取响应内容指令
  // -------------------------------------------------------------------
  this->device->streamPrintfClear(HTTP_BASE_READ_CMD, this->tid);
  if (this->wait(5000, HTTP_BASE_READ_RES) == AT_RCODE1) {
    this->device->streamSkipUntil(','); // 跳过 <httpid>
    this->device->streamSkipUntil(','); // 跳过 <type>
    this->device->streamSkipUntil(','); // 跳过 <unread_length>
  } else {
    return CONNECT_ERR_0;
  }

  // -------------------------------------------------------------------
  // 读取全部响应内容
  // -------------------------------------------------------------------
  size_t contentLength = this->device->streamGetInt(16, ',');
  char *contentBody = (char *)MEM_ALLOC(contentLength + 1);
  for (size_t idx = 0; idx < contentLength; idx++) {
    while (!this->device->_stream->available()) {
      AT_YIELD();
    }

    contentBody[idx] = this->device->_stream->read();
    contentBody[idx + 1] = '\0';

    AT_YIELD();
  }

  // -------------------------------------------------------------------
  // 释放HTTP资源
  // -------------------------------------------------------------------
  this->device->streamPrintfClear(HTTP_BASE_CLOSE, this->tid);
  this->device->streamReleaseInvalidLegacyData();

  // -------------------------------------------------------------------
  // 响应内容回调
  // -------------------------------------------------------------------
  size_t res = fun(contentLength, contentBody);

  free(contentBody);

  return res;
}

size_t AtNetworkHttpML307::executeRequest(HttpCallback fun, const char *serverHost) {
  // 创建HTTP实例----------------------------------------------------
  this->device->streamPrintfClear(HTTP_BASE_READY_0, serverHost);
  if (this->wait(5000, HTTP_BASE_READY_0R) == AT_RCODE1) {
    this->tid = this->device->streamGetInt(8, '\n');
  } else {
    return CONNECT_ERR_0;
  }

  // 设置请求参数----------------------------------------------------
  this->device->streamPrintfClear(HTTP_BASE_CONFIG_1, this->tid);
  this->device->streamPrintfClear(HTTP_BASE_CONFIG_2, this->tid);
  this->device->streamReleaseInvalidLegacyData();

  return AT_RCODE1;
}
